#!/home/wcaarls/compile/bin/python

import time, re, signal, sys, lockdict

base = ""
alpha = 0
labda = 0
mu = 0
dim = 0
results = lockdict.lockdict()

def setstate(state):
  global base
  
  f = open(base + "sta", "w")
  print >>f, state
  f.close()

def setalpha(_base, alpha):
  f = open(_base + "cfg", "r")
  lines = f.readlines()
  f.close()

  f = open(_base + "cfg", "w")
  for l in lines:
    m = re.match("(.*) (.*)", l)
    p = m.group(1)
    v = m.group(2)
    if p == "alpha":
      print >>f, str(p) + " " + str(alpha)
    else:
      print >>f, str(p) + " " + str(v)
  f.close()
  
def awaitstate(state):
  global base
  
  while 1:
    try:
      f = open(base + "sta", "r")
      l = f.readline()
      f.close()
    
      if int(l) == state:
        return
      else:
        time.sleep(0.5)
    except:
      try:
        f.close()
      except:
        pass
    
      time.sleep(0.5)
      
      pass

def alldom(l):
  m = list(l[0])
  for i in range(1, len(l)):
    for j in range(len(l[i])):
      if l[i][j] > m[j]:
        m[j] = l[i][j]
        
  return tuple(m)

def dominates(a, b):
  if a == b:
    return False

  for (x, y) in zip(a, b):
    if y < x:
      return False

  return True

def limit(objlist2, limits):
  objlist = []
  for obj in list(set(objlist2)):
    inlimits = True
    for i in range(len(limits)):
      if obj[i] > limits[i]:
        inlimits = False
        break
    if inlimits == True:
      objlist.append(list(obj))
 
  return objlist

def getpareto(archlist, limits=(0.1, 100, 0.1)):
  try:
    objlist = [tuple(obj) for (idx, ind, obj) in archlist]
  except (ValueError, TypeError):
    objlist = [tuple(obj) for obj in archlist]

  objlist = limit(objlist, limits)

  paretolist = []
  for a in objlist:
    pareto = True
    for b in objlist:
      if dominates(b, a):
        pareto = False
        break
    if pareto:
      paretolist.append(a)
      
  return paretolist

def appendout(pop, file, overwrite=0):
  global base
  
  if overwrite:
    f = open(base + file, "w")
  else:
    f = open(base + file, "a")
    print >>f, ""
  
  for obj in pop:
    print >>f, " ".join([str(o) for o in obj])
  f.close()

def writepop(pop, file):
  global base
  
  f = open(base + file, "w")
  print >>f, len(pop)*(dim+1)
  
  for i in range(len(pop)):
    (idx, ind, obj) = pop[i]
    print >>f, str(idx) + " " + " ".join([str(o) for o in obj])
  print >>f, "END"
  f.close()

def readpop(file):
  global base
  
  sel = []
  
  while 1:
    try:
      f = open(base + file, "r")
      n = int(f.readline())
      if n != 0:
        break
    except:
      try:
        f.close()
      except:
        pass
    
      time.sleep(0.5)
      pass
      
  for i in range(n):
    l = f.readline()
    sel.append(int(l))
    
  end = f.readline()
  if end != "END":
    raise RuntimeError(base + file + " doesn't end in END")
  
  f.close()
  
  f = open(base + file, "w")
  print >>f, "0"
  f.close()
  
  return sel

def readparams():
  global base, alpha, labda, mu, dim

  f = open(base + "cfg", "r")
  
  for l in f.readlines():
    m = re.match("(.*) (.*)", l)
    p = m.group(1)
    v = m.group(2)
    
    if p == "alpha":
      alpha = int(v)
    elif p == "lambda":
      labda = int(v)
    elif p == "mu":
      mu = int(v)
    elif p == "dim":
      dim = int(v)
    
  if mu != labda:
    raise RuntimeError("Lambda should be equal to Mu")
    
def run(_base, create, variate, output, generations=50):
  global base, results

  base = _base
  noise = 0.0
  nr = 1

  print "% (0) Creating initial population"

  setstate(0)

  # Read parameters
  readparams()
  
  results = lockdict.lockdict()
  for i in range(alpha):
    create(results, noise, nr)
  
  archive = []
  results.lock()
  for r in results.iterkeys():
    while len(results[r]) < nr:
      results.unlock()
      time.sleep(0.25)
      results.lock()

    output(r, results[r])
    archive.append((len(archive), r, alldom(results[r])))
  results.unlock()

  pareto = getpareto(archive)
  appendout(pareto, "out", 1)
    
  writepop(archive, "ini")

  print "% (1) Awaiting selection"

  setstate(1)
  
  for g in range(generations):
    awaitstate(2)
    
    print "% (2) Varying selection"
    
    selection = readpop("sel")
    readpop("arc")

    print "%     Selection is " + str(selection)
    
    results = lockdict.lockdict()
    for i in selection:
      variate(archive[i][1], results, noise, nr)

    pop = []
    TO = time.time() + 300

    results.lock()
    for r in results.iterkeys():
      while len(results[r]) < nr and TO > time.time():
        results.unlock()
        time.sleep(0.25)
        results.lock()
      
      if time.time() >= TO:
        print "pisa.run: " + str(r) + " didn't complete"
        print results
        raise RuntimeError
      
      output(r, results[r])
      pop.append((len(archive), r, alldom(results[r])))
      archive.append((len(archive), r, alldom(results[r])))
    results.unlock()
    
    pareto.extend(getpareto(pop))
    pareto = getpareto(pareto)
    appendout(pareto, "out")
    
    writepop(pop, "var")
    
    print "% (3) Awaiting selection"
    
    setstate(3)

def printresults(nr, frame):
    print "Signalled"
    results.lock()
    for r in results:
      print r, results[r]
    results.unlock()

# Install signal handler
print "% Installing signal handler"
signal.signal(signal.SIGHUP, printresults)

